/**
 * Copyright (C),2011-2012,北京国电通网络技术有限公司.
 * FileName:	utils.cpp
 * Author:		LiuHaifeng
 * Version:		V0.1
 * Date:		2011-11-15
 * Description	This file realizes all kinds of useful function used everywhere in all program.
 */
/**
 * History:
 * 		Author		date		Version		Description
 * 	  LiuHaifeng  2012-01-05	  V0.2      add alarm module
 */

#include "utils.h"
#include "../sqlite/sqlite.h"

extern struct StEquipList g_devList;
extern struct StDownTask g_downTask;
extern struct StUpTask g_upTask;
extern struct StOther g_other;
extern struct StDataTransmit g_dataTrans;
extern struct StDelay g_sendDelay;

/***insertElem() brief insert element into special list
 * 	param list[in], list to be inserted to
 *  param elem[in], the number order in list-array
 *
 * 	retval void
 ***/
void insertElem(struct StListHead& list,int elem)
{
	int l_cur,l_last;		///current location and last location of list
	int compVal;			///save priority or controlTime
	switch(list.type)
	{
	case StEquipList_empty:			///g_devList.st_empty---insert at the front of list
		g_devList.st_equipArray[elem].next=g_devList.st_empty.head;
		g_devList.st_empty.head=elem;
		break;
	case StEquipList_equip:			///g_devList.st_equip---insert at the front of list
		g_devList.st_equipArray[elem].next=g_devList.st_equip.head;
		g_devList.st_equip.head=elem;
		break;
	case StDownTask_emtpy:			///g_downTask.st_emtpy---insert at the front of list
		g_downTask.st_command[elem].next=g_downTask.st_emtpy.head;
		g_downTask.st_emtpy.head=elem;
		break;
	case StDownTask_task:			///g_downTask.st_task---insert by priority decrement
		compVal=g_downTask.st_command[elem].priority;
		l_cur=l_last=g_downTask.st_task.head;
		while(l_cur!=NO_MORE && g_downTask.st_command[l_cur].priority>=compVal)
		{
			l_last=l_cur;
			l_cur=g_downTask.st_command[l_cur].next;
		}
		if(l_cur==l_last)			///empty list
		{
			g_downTask.st_task.head=elem;
		}
		else
		{
			g_downTask.st_command[l_last].next=elem;
		}
		g_downTask.st_command[elem].next=l_cur;
		break;
	case StDownTask_timeTask:		///g_downTask.st_timeTask---insert by controlTime increment
		compVal=g_downTask.st_command[elem].controlTime;
		l_cur=l_last=g_downTask.st_timeTask.head;
		while(l_cur!=NO_MORE && g_downTask.st_command[l_cur].controlTime<=compVal)
		{
			l_last=l_cur;
			l_cur=g_downTask.st_command[l_cur].next;
		}
		if(l_cur==l_last)
		{
			g_downTask.st_timeTask.head=elem;
		}
		else
		{
			g_downTask.st_command[l_last].next=elem;
		}
		g_downTask.st_command[elem].next=l_cur;
		break;
	case StUpTask_emtpy:				///g_upTask.st_emtpy---insert at the front of list
		g_upTask.st_recvData[elem].next=g_upTask.st_emtpy.head;
		g_upTask.st_emtpy.head=elem;
		break;
		/* 2012-02-10 V0.2 modify by LiuHaifeng begin */
	case StUpTask_safeguardList:		///g_upTask.st_safeguardList---insert at the end of list
		g_upTask.st_recvData[elem].next=g_upTask.st_safeguardList.head;
		g_upTask.st_safeguardList.head=elem;
		break;
		/* 2012-02-10 V0.2 modify by LiuHaifeng end */
	default:
		break;
	}
}
/***getElem() brief get the first element and remove it from special list
 * 	param list[in], list to be inquiried
 *
 * 	retval int,	position in list-array, or -1 failed.
 ***/
int getElem(struct StListHead& list)
{
	int l_ret=-1;
	if(list.head==NO_MORE)
	{
//		ERROROUT("list is empty!");
		return -1;
	}
	switch(list.type)
	{
	case StEquipList_empty:			///g_devList.st_empty---get from head
		l_ret=g_devList.st_empty.head;
		g_devList.st_empty.head=g_devList.st_equipArray[l_ret].next;
		g_devList.st_equipArray[l_ret].next=NO_MORE;
		break;
	case StDownTask_emtpy:			///g_downTask.st_emtpy---get from head
		l_ret=g_downTask.st_emtpy.head;
		g_downTask.st_emtpy.head=g_downTask.st_command[l_ret].next;
		g_downTask.st_command[l_ret].next=NO_MORE;
		break;
	case StDownTask_task:			///g_downTask.st_task---get from head
		l_ret=g_downTask.st_task.head;
		g_downTask.st_task.head=g_downTask.st_command[l_ret].next;
		g_downTask.st_command[l_ret].next=NO_MORE;
		break;
	case StDownTask_timeTask:		///g_downTask.st_timeTask---get from head
		l_ret=g_downTask.st_timeTask.head;
		g_downTask.st_timeTask.head=g_downTask.st_command[l_ret].next;
		g_downTask.st_command[l_ret].next=NO_MORE;
		break;
	case StUpTask_emtpy:			///g_upTask.st_emtpy---get from head
		l_ret=g_upTask.st_emtpy.head;
		g_upTask.st_emtpy.head=g_upTask.st_recvData[l_ret].next;
		g_upTask.st_recvData[l_ret].next=NO_MORE;
		break;
	case StUpTask_safeguardList:	///g_upTask.st_safeguardList---get from head
		l_ret=g_upTask.st_safeguardList.head;
		g_upTask.st_safeguardList.head=g_upTask.st_recvData[l_ret].next;
		g_upTask.st_recvData[l_ret].next=NO_MORE;
		break;

	default:
		break;
	}
	return l_ret;
}
/***removeElem() brief remove element from special list
 * 	param list[in], list to be inquiried
 *  param num[in], the pos of element in list
 *
 * 	retval int,	0 successful, or -1 failed.
 ***/
int removeElem(struct StListHead& list,int pos)
{
	int l_cur,l_next;
	if(pos<0)
	{
		ERROROUT("no this position in list!");
		return -1;
	}
	switch(list.type)
	{
	case StEquipList_equip:			///g_devList.st_equip
		l_cur=l_next=g_devList.st_equip.head;
		while(l_next!=NO_MORE && l_next!=pos)
		{
			l_cur=l_next;
			l_next=g_devList.st_equipArray[l_next].next;
		}
		if(NO_MORE==l_next)			///empty list
		{
			ERROROUT("no this element!");
			return -1;
		}
		else if(l_cur==l_next)		///is head
		{
			g_devList.st_equip.head=g_devList.st_equipArray[l_cur].next;
		}
		else
		{
			g_devList.st_equipArray[l_cur].next=g_devList.st_equipArray[l_next].next;
		}
		memset(&g_devList.st_equipArray[l_next],0,sizeof(struct StEquipment));
		insertElem(g_devList.st_empty,l_next);
		break;

	case StDownTask_task:			///g_downTask.st_task
		l_cur=l_next=g_downTask.st_task.head;
		while(l_next!=NO_MORE && l_next!=pos)
		{
			l_cur=l_next;
			l_next=g_downTask.st_command[l_next].next;
		}
		if(NO_MORE==l_next)	///empty list
		{
			ERROROUT("no this element!");
			return -1;
		}
		else if(l_cur==l_next)
		{
			g_downTask.st_task.head=g_downTask.st_command[l_cur].next;;
		}
		else
		{
			g_downTask.st_command[l_cur].next=g_downTask.st_command[l_next].next;
		}
		memset(&g_downTask.st_command[l_next],0,sizeof(struct StControlCmd));
		insertElem(g_downTask.st_emtpy,l_next);
		break;

	case StDownTask_timeTask:			///g_downTask.st_timeTask
		l_cur=l_next=g_downTask.st_timeTask.head;
		while(l_next!=NO_MORE && l_next!=pos)
		{
			l_cur=l_next;
			l_next=g_downTask.st_command[l_next].next;
		}
		if(NO_MORE==l_next)	///empty list
		{
			ERROROUT("no this element!");
			return -1;
		}
		else if(l_cur==l_next)
		{
			g_downTask.st_timeTask.head=g_downTask.st_command[l_cur].next;
		}
		else
		{
			g_downTask.st_command[l_cur].next=g_downTask.st_command[l_next].next;
		}
		memset(&g_downTask.st_command[l_next],0,sizeof(struct StControlCmd));
		insertElem(g_downTask.st_emtpy,l_next);
		break;

	case StUpTask_safeguardList:			///g_devList.st_equip
		l_cur=l_next=g_upTask.st_safeguardList.head;
		while(l_next!=NO_MORE && l_next!=pos)
		{
			l_cur=l_next;
			l_next=g_upTask.st_recvData[l_next].next;
		}
		if(NO_MORE==l_next)			///empty list
		{
			ERROROUT("no this element!");
			return -1;
		}
		else if(l_cur==l_next)		///is head
		{
			g_upTask.st_safeguardList.head=g_upTask.st_recvData[l_cur].next;
		}
		else
		{
			g_upTask.st_recvData[l_cur].next=g_upTask.st_recvData[l_next].next;
		}
		memset(&g_upTask.st_recvData[l_next],0,sizeof(struct StReplyData));
		insertElem(g_upTask.st_emtpy,l_next);
		break;

	default:
		goto NOELEM;
		break;
	}
	return 0;

	NOELEM:
		ERROROUT("haven't the element in list!");
		return -1;
}
/***judgeCheckSum() brief check checkSum right or not
 * param	pch[in], point of data to be checked
 * param 	len[in], data length in byte to be checked
 *
 * retval  	bool, true if right or false
 ***/
bool judgeCheckSum(unsigned char* pch,int len)
{
	unsigned char l_cs=0;
	for(int l_aa=0;l_aa<len;l_aa++)
	{
		l_cs+=pch[l_aa];
	}
	if(l_cs!=pch[len])
	{
		ERROROUT("CHeck SUM error!");
		return false;
	}
	return true;
}
/***charToUnsigned() brief change 'char' to 'unsigned char'
 * param	pch[in][out], point of data to be changed, and return next to be changed
 *
 * retval  	unsigned char, result after change.
 ***/
unsigned char charToUnsigned(char** pch)
{
	bool l_stop=false;
	unsigned char l_val=0;
	NEXT:
	if((**pch<='f')&&('a'<=**pch))
	{
		l_val+=**pch-'a'+10;
	}
	else if((**pch<='F')&&('A'<=**pch))
	{
		l_val+=**pch-'A'+10;
	}
	else if((**pch<='9')&&('0'<=**pch))
	{
		l_val+=**pch-'0';
	}
	else
	{
		ERROROUT("the char is not in [a-f][A-F][0-9]!");
		g_other.st_charToUnsignedFlag=false;		///indicate some fault format happened!
	}
	(*pch)++;

	if(l_stop)
		goto END;
	else
		l_stop=true;
	l_val=l_val*16;
	goto NEXT;

	END:
	return l_val;
}
/***creatChecksum() brief calculate checksum.
 *param num[in], the number byte to add together, who's sum is checksum.
 *
 *retval unsigned char, checksum.
 ***/
unsigned char creatChecksum(int num)
{
	assert(num>0);

	unsigned char l_cs=0;
	for(int l_temp=0;l_temp<num;l_temp++)
	{
		l_cs+=g_dataTrans.st_sendSerial[l_temp];
	}
	return l_cs;
}
/***myDelay() brief implement delay function.
 *	param 	delay[in], 'ms' to delay.
 *
 *	retval  void, null
 ***/
void myDelay(int delay)
{
	if(delay<=0)
		return;
	struct timeval timeout;
	timeout.tv_sec=delay/1000;
	timeout.tv_usec=(delay%1000)*1000;			///ms
	select(0,NULL,NULL,NULL,&timeout);
}
/***findByID() brief find special device by typeID/operID/socketID/safeguardID
 *	param 	ID[in], device's speical ID.
 *
 *	retval  void, null
 ***/
int findByID(int ID,int type)
{
	if(find_typeID==type)
	{
		for(int i=g_devList.st_equip.head;i!=NO_MORE;i=g_devList.st_equipArray[i].next)
			if(g_devList.st_equipArray[i].typeID==ID)
			{
				return i;
			}
	}
	else if(find_operID==type)
	{
		for(int i=g_devList.st_equip.head;i!=NO_MORE;i=g_devList.st_equipArray[i].next)
			if(g_devList.st_equipArray[i].operID==ID)
			{
				return i;
			}
	}
	return -1;
}
int findByPoint(unsigned char* pos,int type)
{
	if(find_socketID==type)
	{
		for(int i=g_devList.st_equip.head;i!=NO_MORE;i=g_devList.st_equipArray[i].next)
			if(g_devList.st_equipArray[i].equipmentID[0]==pos[0] && g_devList.st_equipArray[i].equipmentID[1]==pos[1] && \
					g_devList.st_equipArray[i].equipmentID[2]==pos[2] && g_devList.st_equipArray[i].equipmentID[3]==pos[3] && \
					g_devList.st_equipArray[i].equipmentID[4]==pos[4] && g_devList.st_equipArray[i].equipmentID[5]==pos[5])
			{
				return i;
			}
	}
	else if(find_safeguardID==type)
	{
#if defined DINAIKE
		for(int i=g_devList.st_equip.head;i!=NO_MORE;i=g_devList.st_equipArray[i].next)
			if(g_devList.st_equipArray[i].equipmentID[0]==pos[0] && g_devList.st_equipArray[i].equipmentID[1]==pos[1])
#else
		for(int i=g_devList.st_equip.head;i!=NO_MORE;i=g_devList.st_equipArray[i].next)
			if((g_devList.st_equipArray[i].equipmentID[0]==pos[0] && g_devList.st_equipArray[i].equipmentID[1]==pos[1] && \
					g_devList.st_equipArray[i].equipmentID[2]==pos[2] && g_devList.st_equipArray[i].equipmentID[3]==pos[3]) || \
					(g_devList.st_equipArray[i].equipmentID[4]==pos[0] && g_devList.st_equipArray[i].equipmentID[5]==pos[1] && \
					g_devList.st_equipArray[i].equipmentID[6]==pos[2] && g_devList.st_equipArray[i].equipmentID[7]==pos[3]))
#endif
			{
				return i;
			}
	}

	return -1;
}
/***needDelay() brief justify if need delay
 *	param typeID[in], device's typeID
 *
 *	retval  int, ms to delay
 ***/
int needDelay(int typeID)
{
	int l_delay=-1;
	struct timeval l_tv;
	if(-1==gettimeofday(&l_tv,NULL))
	{
		ERROROUT("get-time failed!");
		return -1;
	}
	PRINTOUT("need system time = %d",l_tv.tv_sec);
	///make sure have 1000ms delay
	if(!g_sendDelay.st_smart)
		l_delay=1000-(l_tv.tv_usec-g_sendDelay.st_lastSend.tv_usec)/1000-(l_tv.tv_sec-g_sendDelay.st_lastSend.tv_sec)*1000;

	PRINTOUT("l_delay = %d",l_delay);
	if(l_delay<=0)
		g_sendDelay.st_lastSend=l_tv;
	else
	{
		g_sendDelay.st_lastSend.tv_usec=(l_tv.tv_usec+l_delay*1000)%1000000;
		g_sendDelay.st_lastSend.tv_sec=l_tv.tv_sec+(l_tv.tv_usec+l_delay*1000)/1000000;
	}

	if(0x68==g_dataTrans.st_sendSerial[0])
		g_sendDelay.st_smart=false;
	else
		g_sendDelay.st_smart=true;

	PRINTOUT("delay is: %d",l_delay);

	return l_delay;
}
/***sendService() brief send result to webservice
 * param kind[in], indicate successful(00)/fail(ff) or NoResult -1.
 *
 * retval void
 ***/
void sendService(int kind)
{
	int l_sendNum=0;

	if(send_only==kind)				///just send
		goto END;
	else if(err_timeout==kind)		///if operate time-out
	{
		l_sendNum++;
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='\0';
		goto END;
	}
	else if(err_format==kind)		///if error format
	{
		l_sendNum++;
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';

		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='&';
		g_other.st_shmADDR[l_sendNum++]='f';
		g_other.st_shmADDR[l_sendNum++]='1';
		g_other.st_shmADDR[l_sendNum++]='#';
		g_other.st_shmADDR[l_sendNum++]='\0';
		goto END;
	}
	else if(err_formatpro==kind)		///if error format
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='1';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_socket==kind)		///if error socket
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='2';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_database==kind)		///if error database
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='3';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_memory==kind)		///if error memory
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='4';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_serial==kind)		///if error serial
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='5';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_other==kind)		///if error other
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='f';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	else if(err_no==kind)
	{
		g_other.st_pCmdOther[l_sendNum++]='&';
		g_other.st_pCmdOther[l_sendNum++]='0';
		g_other.st_pCmdOther[l_sendNum++]='0';
		g_other.st_pCmdOther[l_sendNum++]='#';
	}
	g_other.st_pCmdOther[l_sendNum]='\0';

	///send data to webservice
	END:
	if (inDispose()||isCMDFlag())
		setResult();
}
